package cc.rengu.igas.channel.cups.core.service.base;

import cc.rengu.igas.channel.cups.common.constant.CupsParamConstant;
import cc.rengu.igas.channel.cups.common.constant.CupsTreeNodeConstant;
import cc.rengu.igas.channel.cups.core.model.ChnlBizResponse;
import cc.rengu.igas.channel.cups.facade.base.BaseRequest;
import cc.rengu.igas.channel.cups.facade.bean.CupsTermInfo;
import cc.rengu.oltp.service.base.RadpService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.DstChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.DstChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.DstChannelInfo;
import cc.rengu.oltp.service.common.entity.DstTxnAuthCfg;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSON;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;

/**
 * 预授权业务处理基类
 */
public abstract class PreAuthService<T> extends RadpService {
    @Override
    protected int bizInit(String s) {
        return 0;
    }

    @Override
    protected int bizProcess(String s, int i) {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        try {
            /* Step1：通道(交易)权限检查 */
            rglog.info("---------------> 通道(交易)权限检查 <---------------");
            channelPermissionCheck();
            /* Step2：业务处理前实现接口 */
            rglog.info("---------------> 业务处理前处理 <---------------");
            T request = beforeBizProcess();

            /* Step3：公共字段统一处理 */

            /* Step4：业务逻辑处理 */
            rglog.info("---------------> 业务逻辑处理 <---------------");
            ChnlBizResponse response = callBizService(request);
            /* Step4：业务处理后实现接口 */
            rglog.info("---------------> 业务处理后处理 <---------------");
            afterBizProcess(response);
        } catch (Exception e) {
            String respCode;
            String respDesc;
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.error("业务异常信息:<{}>", byteArrayOutputStream.toString());
            if (e instanceof BizException) {
                respCode = ((BizException) e).getCode();
                respDesc = e.getMessage();
                rglog.error("业务处理失败，业务返回码:<{}>，业务返回信息:<{}>", respCode, respDesc);
            } else {
                rglog.error("系统处理失败，返回信息:<{}>", e);
                respCode = OltpRpcdEnum.OLTP_PROCESS_ERROR.getRespCode();
                respDesc = OltpRpcdEnum.OLTP_PROCESS_ERROR.getRespDesc();
            }
            try {
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE, respCode);
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC, respDesc);
            } catch (Exception ex) {
                ex.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
                rglog.error("设置节点值异常信息:<{}>", byteArrayOutputStream.toString());
                return -1;
            }

        }
        return 0;
    }

    @Override
    protected int bizTerminate(String s) {
        return 0;
    }

    /**
     * 业务调用前处理
     *
     * @return 业务处理请求结构
     */
    protected abstract T beforeBizProcess() throws Exception;

    /**
     * 业务处理服务调用
     *
     * @param request 业务处理信息
     * @return 业务处理应答结果
     */
    protected abstract ChnlBizResponse callBizService(T request) throws Exception;

    /**
     * 业务调用后处理
     *
     * @param response 业务响应结果
     */
    protected abstract void afterBizProcess(ChnlBizResponse response) throws Exception;

    /**
     * 通道、交易权限权限
     *
     * @throws Exception 业务处理异常
     */
    private void channelPermissionCheck() throws Exception {
        BaseRequest baseRequest = new BaseRequest();
        ConvertUtil.convertOutput(baseRequest);
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String instId = baseRequest.getHeader().getInstId();
        String txnNum = baseRequest.getHeader().getTxnNum();
        /* 通道状态检查 */
        String dstChannelKey = instId + ChannelEnum.CUPS.getChannelType();
        DstChannelInfo dstChannelInfo = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_ISS_INFO_CACHE, dstChannelKey), DstChannelInfo.class);
        if (null == dstChannelInfo) {
            DstChannelInfoMapper dstChannelInfoMapper = new DstChannelInfoMapperImpl();
            dstChannelInfo = dstChannelInfoMapper.selectDstChannelInfoByPrimaryKey(instId, ChannelEnum.CUPS.getChannelType());
        }
        if (null == dstChannelInfo || !dstChannelInfo.getDstChannelStatus().equalsIgnoreCase(AppParamConstant.YES)) {
            rglog.error("支付渠道<{}-{}>未配置或已停用！", ChannelEnum.CUPS.getChannelType(), (null == dstChannelInfo) ? "" : dstChannelInfo.getDstChannelName());
            throw new BizException(OltpRpcdEnum.CHANNEL_DISABLED);
        }
        xmlTreeUtil.setXmlTreeObjectValue(CupsTreeNodeConstant.DST_CHANNEL_INFO, dstChannelInfo);

        String dstChannelAuthKey = instId.trim() + ChannelEnum.CUPS.getChannelType() + txnNum.trim();
        DstTxnAuthCfg dstTxnAuthCfg = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_TXN_CACHE, dstChannelAuthKey), DstTxnAuthCfg.class);
        if (null == dstTxnAuthCfg || !dstTxnAuthCfg.getSupportFlag().toUpperCase().equals(AppParamConstant.YES)) {
            rglog.error("支付通道<{}-{}>不支持此交易，通道交易码:<{}>", dstChannelInfo.getDstChannelId(), dstChannelInfo.getDstChannelName(), txnNum);
            throw new BizException(OltpRpcdEnum.TRANS_NOT_SUPPORT);
        }
        if (dstTxnAuthCfg.getMsgRegisterFlag() != null && dstTxnAuthCfg.getMsgRegisterFlag().isEmpty()) {
            xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.MSG_REG_FLAG, dstTxnAuthCfg.getMsgRegisterFlag());
        }
    }

    /**
     * 组银联60域
     *
     * @param msgType         消息类型-非冲正、确认类交易不填或者填0000
     * @param termRead        终端读取能力
     * @param icConCode       IC卡条件代码
     * @param noPinFlag       小额免密
     * @param specialBillType 特殊计费
     *                        termType
     *                        01-ATM
     *                        02-传统pos
     *                        03-mPOS
     *                        04-智能pos
     * @return 60域信息
     */
    protected String packF060Field(String msgType, String termRead, String icConCode,
                                   String noPinFlag, String specialBillType, String termType, String algorithm) {
        StringBuilder buf = new StringBuilder();
        if (msgType == null) {
            msgType = "0000";
        }
        buf.append(msgType);
        /*60.2.1-账户所有人类型*/
        buf.append("0");
        /*60.2.2-终端读取能力*/
        if (!StringUtil.isEmptyOrNull(termRead)) {
            buf.append(termRead);
        } else {
            buf.append("0");
        }
        /*60.2.3-IC卡条件代码*/
        if (!StringUtil.isEmptyOrNull(icConCode)) {
            buf.append(icConCode);
        } else {
            buf.append("0");
        }
        /*60.2.4-保留使用*/
        buf.append("0");
        /*60.2.5-终端类型  */
        if ("01".equals(termType)) {
            buf.append("01");
        } else if ("02".equals(termType)) {
            buf.append("03");
        } else if ("03".equals(termType) || "04".equals(termType)) {
            buf.append("11");
        } else if ("06".equals(termType)) {
            buf.append("06");
        } else {
            buf.append("00");
        }
        /*60.2.6-受理免验密码标志  */
        if ("1".equals(noPinFlag)) {
            buf.append("1");
        } else {
            buf.append("0");
        }
        /*60.2.7-IC卡验证可靠性标志  */
        buf.append("1");
        /*60.2.8-电子商务标志  */
        buf.append("00");
        /*60.2.9-交互方式标志  */
        buf.append("0");

        /*60.3.1-特殊计费类型*/
        /*60.3.2-特殊计费档次*/
        if (specialBillType != null) {
            buf.append(specialBillType);
        } else {
            buf.append("000");
        }
        /*60.3.3-保留使用（第 3 位为 MAC 算法标识）*/
        if ("SM4".equals(algorithm)) {
            buf.append("004");
        } else {
            buf.append("000");
        }
        /*60.3.4-支持部分承兑和返回余额标志*/
        buf.append("1");
        /*60.3.5-交易发起方式*/
        if ("0620".equals(msgType)) {
            buf.append("0");  //IC脚本结果通知
        } else {
            buf.append("1");
        }
        return buf.toString();
    }

    /**
     * 银联104域-PI用法
     *
     * @param cupsTermInfo 终端信息
     * @return 104域信息
     */
    protected String packF104Pi(CupsTermInfo cupsTermInfo) throws Exception {

        if (cupsTermInfo == null) {
            return null;
        }
        StringBuilder buf = new StringBuilder();
        if (cupsTermInfo.getLongitude() != null) {
            buf.append("01");
            //buf.append(String.format("%03d", cupsTermInfo.getLongitude().length()));
            buf.append(Integer.toHexString(cupsTermInfo.getLongitude().length()).length() == 1
                    ? "0" + Integer.toHexString(cupsTermInfo.getLongitude().length()).toUpperCase() : Integer.toHexString(cupsTermInfo.getLongitude().length()).toUpperCase());
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getLongitude().getBytes(CupsParamConstant.GB18030)));
        }
        if (cupsTermInfo.getLatitude() != null) {
            buf.append("02");
            //buf.append(String.format("%03d", cupsTermInfo.getLatitude().length()));
            buf.append(Integer.toHexString(cupsTermInfo.getLatitude().length()).length() == 1
                    ? "0" + Integer.toHexString(cupsTermInfo.getLatitude().length()).toUpperCase() : Integer.toHexString(cupsTermInfo.getLatitude().length()).toUpperCase());
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getLatitude().getBytes(CupsParamConstant.GB18030)));
        }
        if (cupsTermInfo.getNetworkLicense() != null) {
            buf.append("03");
            buf.append("05");
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getNetworkLicense().getBytes(CupsParamConstant.GB18030)));
        }
        if (cupsTermInfo.getDeviceType() != null) {
            buf.append("04");
            buf.append("02");
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getDeviceType().getBytes(CupsParamConstant.GB18030)));
        }
        if (cupsTermInfo.getSerialNum() != null) {
            buf.append("05");
            buf.append(Integer.toHexString(cupsTermInfo.getSerialNum().length()).length() == 1
                    ? "0" + Integer.toHexString(cupsTermInfo.getSerialNum().length()).toUpperCase() : Integer.toHexString(cupsTermInfo.getSerialNum().length()).toUpperCase());
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getSerialNum().getBytes(CupsParamConstant.GB18030)));
        }
        if (cupsTermInfo.getEncryptRandNum() != null) {
            buf.append("06");
            buf.append(Integer.toHexString(cupsTermInfo.getEncryptRandNum().length()).length() == 1
                    ? "0" + Integer.toHexString(cupsTermInfo.getEncryptRandNum().length()).toUpperCase() : Integer.toHexString(cupsTermInfo.getEncryptRandNum().length()).toUpperCase());
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getEncryptRandNum().getBytes(CupsParamConstant.GB18030)));
        }
        if (cupsTermInfo.getSecretText() != null) {
            buf.append("07");
            buf.append("08");
            //base64值转为hex
            buf.append(StringUtil.binaryToHexString(StringUtil.base64StringToBinary(cupsTermInfo.getSecretText())));
        }
        if (cupsTermInfo.getAppVersion() != null) {
            buf.append("08");
            buf.append(Integer.toHexString(cupsTermInfo.getAppVersion().length()).length() == 1
                    ? "0" + Integer.toHexString(cupsTermInfo.getAppVersion().length()).toUpperCase() : Integer.toHexString(cupsTermInfo.getAppVersion().length()).toUpperCase());
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getAppVersion().getBytes(CupsParamConstant.GB18030)));
        }
        String f104Field = ("PI" + String.format("%03d", buf.toString().length() / 2));
        return StringUtil.binaryToHexString(f104Field.getBytes(CupsParamConstant.GB18030)) + buf.toString();
    }

    /**
     * 获取银联清算日期
     *
     * @param oriDate 交易日期
     * @return 银联清算日期
     */
    protected String getCupsSettleDate(String oriDate) {
        String dateTime = DateUtil.getCurrentDate();
        String year = dateTime.substring(0, 4);
        String date = dateTime.substring(4, 8);
        if (date.equals(oriDate)) {
            return dateTime;
        } else if ("0101".equals(oriDate) && DateUtil.compareDate(year + oriDate, dateTime) < 0) {
            return String.format("%d", Integer.parseInt(year) + 1) + oriDate;
        } else if ("1231".equals(oriDate) && "0101".equals(date)) {
            return String.format("%d", Integer.parseInt(year) - 1) + oriDate;
        }
        return year + oriDate;
    }

    /**
     * 生成外围系统流水号
     *
     * @param instId
     * @param sysSeqNo
     * @return
     */
    protected String genServiceSn(String instId, String sysSeqNo) {
        /*3位法人行号+4位系统标识+000+2位序号+9+6位流水号*/
        return instId + CupsParamConstant.SYS_ID + "0000" + sysSeqNo.substring(32) + "9" + sysSeqNo.substring(26, 32);
    }
}
